package com.zzx.auth.oauth2;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * Token 配置
 */
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "spring.security.oauth2.server")
public class TokenConfig {
    /**
     * JWT密钥
     */
    private String signingKey = "test";

    /**
     * JWT 令牌转换器
     *
     * @return JwtAccessTokenConverter
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwt = new JwtAccessTokenConverter() {

            @Override
            protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;
                Set<String> tokenScope = token.getScope();
                String scopeTemp = " ";
                if (tokenScope != null && tokenScope.size() > 0) {
                    scopeTemp = tokenScope.iterator().next();
                }
                String scope = scopeTemp;
                LoginUser user = (LoginUser) authentication.getUserAuthentication().getPrincipal();
                // 自定义过期时间(数据库已设置)
//                token.setExpiration(new Date().getTime()+30*60*60*1000);
                // 自定义信息
                Map<String, Object> data = new HashMap<String, Object>(4) {{
                    put("user_id", user.getUserId());
                    put("user_type", user.getUserType());
                    put("code", UUID.randomUUID().toString());
                    put("nickName", user.getNickName());
                    put("scope", scope);
                }};
                token.setAdditionalInformation(data);

                return super.encode(accessToken, authentication);
            }

            @Override
            protected Map<String, Object> decode(String token) {
                // JWT续约 -- 因为每次使用都会解析JWT 也说明用户活跃使用则对其续约
                Map<String, Object> decode = super.decode(token);
             /*   // 过期时间 判断 renewTime
                if(decode.containsKey("exp")) {
                    long new_timeout = System.currentTimeMillis() + ttl;
                    decode.put("exp", new_timeout / 1000);
                }*/
                return decode;
            }
        };
        jwt.setSigningKey(signingKey);
        return jwt;
    }

    /**
     * 配置 token 如何生成 <br/>
     * 1. 默认 InMemoryTokenStore 基于内存存储 <br/>
     * 2.     JdbcTokenStore 基于数据库存储 <br/>
     * 3.     JwtTokenStore 使用 JWT 存储 该方式可以让资源服务器自己校验令牌的有效性
     * 而不必远程连接认证服务器再进行认证。<br/>
     */
    @Bean
    public TokenStore tokenStore() {
        return new CustomJwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * 基于JDBC存储令牌
     * @author xz
     * @date 2020/6/10
     */
//    @Bean
//    public TokenStore tokenStore(DataSource dataSource) {
//        return new JdbcTokenStore(dataSource);
//    }

    /**
     * 基于JVM存储令牌
     *
     * @author xz
     * @date 2020/6/10
     */
//    @Bean
//    public TokenStore tokenStore() {
//         return new InMemoryTokenStore();
//    }
    public String getSigningKey() {
        return signingKey;
    }

    public void setSigningKey(String signingKey) {
        this.signingKey = signingKey;
    }
}
